/* -*- coding: utf-8 -*- */
/*  -*- C++ -*- */

%{
#include <stdio.h>
#include <string>
#include <vector>
#include <sstream>

  //#include "expression.h"
%}

/* Require bison 2.3 or later */
%require "2.3"

/* add debug output code to generated parser. disable this for release
 * versions. */
%debug

/* write out a header file containing the token defines */
%defines

/* use newer C++ skeleton file */
%skeleton "lalr1.cc"

/* namespace to enclose parser in */
%name-prefix="netthumb"

/* set the parser's class identifier */
%define "parser_class_name" "Parser"

/* keep track of the current position within the input */
%locations
%initial-action
{
    // initialize the initial location object
    @$.begin.filename = @$.end.filename = &driver.streamname;
};


%union {
  std::string* sval;
}

/* The driver is passed by reference to the parser and to the scanner. This
 * provides a simple but effective pure interface, not relying on global
 * variables. */
%parse-param { class Driver& driver }

/* verbose error messages */
%error-verbose

%token <sval> VINT
%token INICIO_BLOQUE
%token FIN_BLOQUE
%token DOSPUNTOS
%token <sval> IP_ADDR
%token <sval> ID
%token END      0 "end of file"

%token NETTHUMB_HOST
%token NETTHUMB_DEV
%token NETTHUMB_LINK
%token NETTHUMB_UP
%token NETTHUMB_DOWN
%token NETTHUMB_ADDR
%token NETTHUMB_NETWORK
%token NETTHUMB_SCOPE
%token NETTHUMB_GLOBAL
%token NETTHUMB_SITE
%token NETTHUMB_ROUTE
%token NETTHUMB_NET
%token NETTHUMB_DEFAULT
%token NETTHUMB_VIA
%token NETTHUMB_METRIC
%token NETTHUMB_PRIORITY
%token NETTHUMB_UNICAST
%token NETTHUMB_UNREACHABLE
%token NETTHUMB_BLACKHOLE
%token NETTHUMB_PROHIBIT
%token NETTHUMB_LOCAL
%token NETTHUMB_BROADCAST
%token NETTHUMB_THROW
%token NETTHUMB_NAT
%token NETTHUMB_ANYCAST
%token NETTHUMB_MULTICAST
%token NETTHUMB_ROUTER
%token NETTHUMB_TYPE
%token NETTHUMB_MTU
%token NETTHUMB_ON
%token NETTHUMB_OFF

%{

#include "driver.h"
#include "scanner.h"

/* this "connects" the bison parser in the driver to the flex scanner class
 * object. it defines the yylex() function call to pull the next token from the
 * current lexer object of the driver context. */
#undef yylex
#define yylex driver.lexer->lex

%}

%%
%start program;

program:
     hosts routers networks
     {
       driver.getContext().visit(driver.getContext().getSymbolTablePtr());
     }
|
     hosts networks
     {
       driver.getContext().visit(driver.getContext().getSymbolTablePtr());
     }
;

hosts:
     hosts host
|
     host
;

host:
     NETTHUMB_HOST ID INICIO_BLOQUE devices route FIN_BLOQUE
     {
       driver.getContext().insertAttribute(HOST_ID, *$2);
       std::ostringstream buffer;
       buffer << @1;
       std::string location = buffer.str();
       driver.getContext().insertAttribute(HOST_LOCATION, 
					   location.substr(0, location.find_first_of("-")));
       driver.getContext().visit(new HostI());
     }
|
     NETTHUMB_HOST error

|
     NETTHUMB_HOST ID error

|
     NETTHUMB_HOST ID INICIO_BLOQUE devices route error

|
     error
;

devices:
     NETTHUMB_DEV ID INICIO_BLOQUE linkDescription netConf FIN_BLOQUE
     {
       driver.getContext().insertAttribute(DEVICE_ID, *$2);
       std::ostringstream buffer;
       buffer << @1;
       std::string location = buffer.str();
       driver.getContext().insertAttribute(DEVICE_LOCATION, 
					   location.substr(0, location.find_first_of("-")));
       driver.getContext().visit(new DeviceI());
     }
|
     NETTHUMB_DEV ID INICIO_BLOQUE linkDescription netConf error
|
     devices NETTHUMB_DEV ID INICIO_BLOQUE linkDescription netConf FIN_BLOQUE
     {
       driver.getContext().insertAttribute(DEVICE_ID, *$3);
       std::ostringstream buffer;
       buffer << @2;
       std::string location = buffer.str();
       driver.getContext().insertAttribute(DEVICE_LOCATION, 
					   location.substr(0, location.find_first_of("-")));
       driver.getContext().visit(new DeviceI());
     }
|
     devices NETTHUMB_DEV ID INICIO_BLOQUE linkDescription netConf error
|
     devices NETTHUMB_DEV error
|
     devices NETTHUMB_DEV ID error
|
     NETTHUMB_DEV error
|
     NETTHUMB_DEV ID error
|
     error
;

linkDescription:
     linkAddr
|
     linkAddr linkStates
;

linkAddr:
     NETTHUMB_LINK DOSPUNTOS ID
     {
       driver.getContext().insertAttribute(DEVICE_LINKID, *$3);
     }
|
     NETTHUMB_LINK error
|
     NETTHUMB_LINK DOSPUNTOS error
;

linkStates:
     NETTHUMB_UP
     {
       driver.getContext().insertAttribute(DEVICE_LINKST, string("up"));
     }
|
     NETTHUMB_DOWN
     {
       driver.getContext().insertAttribute(DEVICE_LINKST, string("down"));
     }
|
     error
;

netConf:
     NETTHUMB_ADDR IP_ADDR NETTHUMB_NETWORK ID NETTHUMB_SCOPE scopeOpt
     {
       driver.getContext().insertAttribute(DEVICE_ADDRID, *$2);
       driver.getContext().insertAttribute(DEVICE_NETID,  *$4);
     }
|
     NETTHUMB_ADDR error
|
     NETTHUMB_ADDR IP_ADDR error
|
     NETTHUMB_ADDR IP_ADDR NETTHUMB_NETWORK error
;

scopeOpt:
     NETTHUMB_GLOBAL
     {
       driver.getContext().insertAttribute(DEVICE_NETSCOPE, string("global"));
     }
|
     NETTHUMB_SITE
     {
       driver.getContext().insertAttribute(DEVICE_NETSCOPE, string("site"));
     }
|
     NETTHUMB_LINK
     {
       driver.getContext().insertAttribute(DEVICE_NETSCOPE, string("link"));
     }
|
     NETTHUMB_HOST
     {
       driver.getContext().insertAttribute(DEVICE_NETSCOPE, string("host"));
     }
|
     error
;

route:
     NETTHUMB_ROUTE INICIO_BLOQUE routeOptionsGroups routeDefOpt FIN_BLOQUE
     {
       std::ostringstream buffer;
       buffer << @1;
       std::string location = buffer.str();
       driver.getContext().insertAttribute(ROUTE_LOCATION,
					   location.substr(0, location.find_first_of("-")));
       driver.getContext().visit(new RouteI());
     }
|
     NETTHUMB_ROUTE INICIO_BLOQUE routeOptionsGroups routeDefOpt error

|
     NETTHUMB_ROUTE error
;

routeOptionsGroups:
     routeOptionsGroups typeR net options
     {
       std::ostringstream buffer;
       buffer << @2;
       std::string location = buffer.str();
       driver.getContext().insertAttribute(CONFROUTE_LOCATION,
					   location.substr(0, location.find_first_of("-")));
       driver.getContext().visit(new ConfRouteI());
     }
|
     typeR net options
     {
       std::ostringstream buffer;
       buffer << @1;
       std::string location = buffer.str();
       driver.getContext().insertAttribute(CONFROUTE_LOCATION,
					   location.substr(0, location.find_first_of("-")));
       driver.getContext().visit(new ConfRouteI());
     }
|
     error
;

typeR:
     NETTHUMB_UNICAST
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("unicast"));
     }
|
     NETTHUMB_UNREACHABLE
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("unreachable"));
     }
|
     NETTHUMB_BLACKHOLE
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("blackhole"));
     }
|
     NETTHUMB_PROHIBIT
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("prohibit"));
     }
|
     NETTHUMB_LOCAL
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("local"));
     }
|
     NETTHUMB_BROADCAST
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("broadcast"));
     }
|
     NETTHUMB_THROW
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("thrown"));
     }
|
     NETTHUMB_NAT
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("nat"));
     }
|
     NETTHUMB_ANYCAST
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("anycast"));
     }
|
     NETTHUMB_MULTICAST
     {
       driver.getContext().insertAttribute(CONFROUTE_NETTYPE, string("multicast"));
     }
|
;

net:
     NETTHUMB_NET ID conf_r
     {
       driver.getContext().insertAttribute(CONFROUTE_NETID, *$2);
     }
|
     NETTHUMB_NET error

;

conf_r:
     NETTHUMB_VIA IP_ADDR NETTHUMB_DEV ID
     {
       driver.getContext().insertAttribute(CONFROUTE_VIAADDR, *$2);
       driver.getContext().insertAttribute(CONFROUTE_DEVICEID, *$4);
       driver.getContext().insertAttribute(ROUTE_VIAADDR, *$2);
       driver.getContext().insertAttribute(ROUTE_DEVICEID, *$4);
     }
|
     NETTHUMB_VIA error

|
     NETTHUMB_VIA IP_ADDR NETTHUMB_DEV error

|
     NETTHUMB_DEV ID
     {
       driver.getContext().insertAttribute(CONFROUTE_DEVICEID, *$2);
       driver.getContext().insertAttribute(ROUTE_DEVICEID, *$2);
     }
|
     NETTHUMB_DEV error
;

options:
     metricPriority VINT
     {
       driver.getContext().insertAttribute(CONFROUTE_METRIC, *$2);
     }
|
     metricPriority error
|
;

metricPriority:
     NETTHUMB_METRIC
     {
       // El par que no sirva sera descartado por el visitor correspondiente.
       driver.getContext().insertAttribute(CONFROUTE_MORP, string("metric"));
       driver.getContext().insertAttribute(ROUTE_MORP, string("metric"));
     }
|
     NETTHUMB_PRIORITY
     {
       // El par que no sirva sera descartado por el visitor correspondiente.
       driver.getContext().insertAttribute(CONFROUTE_MORP, string("priority"));
       driver.getContext().insertAttribute(ROUTE_MORP, string("priority"));
     }
;

routeDefOpt:
     NETTHUMB_DEFAULT conf_r metricPriority VINT
     {
       driver.getContext().insertAttribute(ROUTE_METRIC, *$4);
     }
|
     NETTHUMB_DEFAULT conf_r metricPriority error
|
;

routers:
    routers router
|
    router
;

router:
    NETTHUMB_ROUTER ID INICIO_BLOQUE devices FIN_BLOQUE
    {
      driver.getContext().insertAttribute(ROUTER_ID, *$2);
      std::ostringstream buffer;
      buffer << @1;
      std::string location = buffer.str();
      driver.getContext().insertAttribute(ROUTER_LOCATION,
					  location.substr(0, location.find_first_of("-")));
      driver.getContext().visit(new RouterI);
    }
|
    NETTHUMB_ROUTER error

|
    NETTHUMB_ROUTER ID error

|
    NETTHUMB_ROUTER ID INICIO_BLOQUE devices error

|
    NETTHUMB_ROUTER ID INICIO_BLOQUE devices route FIN_BLOQUE

    {
      driver.getContext().insertAttribute(ROUTER_ID, *$2);
      std::ostringstream buffer;
      buffer << @1;
      std::string location = buffer.str();
      driver.getContext().insertAttribute(ROUTER_LOCATION,
					  location.substr(0, location.find_first_of("-")));
      driver.getContext().visit(new RouterI);
    }
|
    NETTHUMB_ROUTER ID INICIO_BLOQUE devices route error
;

networks:
    networks network
|
    network
;

network:
    NETTHUMB_NETWORK ID INICIO_BLOQUE netType netLink NETTHUMB_ADDR IP_ADDR FIN_BLOQUE
    {
      driver.getContext().insertAttribute(NETWORK_ID, *$2);
      driver.getContext().insertAttribute(NETWORK_ADDRID, *$7);
      std::ostringstream buffer;
      buffer << @$;
      std::string location = buffer.str();
      driver.getContext().insertAttribute(NETWORK_LOCATION,
					  location.substr(0, location.find_first_of("-")));
      driver.getContext().visit(new NetworkI);
    }
|
    NETTHUMB_NETWORK error

|
    NETTHUMB_NETWORK ID error

|
    NETTHUMB_NETWORK ID INICIO_BLOQUE netType netLink error

|
    NETTHUMB_NETWORK ID INICIO_BLOQUE netType netLink NETTHUMB_ADDR error

|
    NETTHUMB_NETWORK ID INICIO_BLOQUE netType netLink NETTHUMB_ADDR IP_ADDR error
;

netType:
    NETTHUMB_TYPE ID
    {
      driver.getContext().insertAttribute(NETWORK_TYPEID, *$2);
    }
|
    NETTHUMB_TYPE error

;

netLink:
    NETTHUMB_LINK NETTHUMB_MTU VINT NETTHUMB_MULTICAST onOff
    {
      driver.getContext().insertAttribute(NETWORK_MTU, *$3);
    }
|
    NETTHUMB_LINK NETTHUMB_MTU error

|
    NETTHUMB_LINK NETTHUMB_MTU VINT NETTHUMB_MULTICAST error
;

onOff:
    NETTHUMB_ON
    {
      driver.getContext().insertAttribute(NETWORK_MULTICAST, string("on"));
    }
|
    NETTHUMB_OFF
    {
      driver.getContext().insertAttribute(NETWORK_MULTICAST, string("off"));
    }
;

%%
void
netthumb::Parser::error (const Parser::location_type& l,
			  const std::string& m)
{
  driver.error (l, m);
}
